﻿using System;
using System.Data;
using System.Data.Common;
using System.Configuration;

using Job.Core.Common;

namespace Job.Core.Data
{
    /// <summary>
    /// 提供跨不同数据库的 ADO.NET 数据操作方法封装(无法继承此类)。
    /// 注意当 Web 应用程序使用 ContinuedConnection 为 true 时，请不要在编程中关闭 DbConnection 对象，应使用注册 DataContextModule 来关闭 DbConnection。
    /// </summary>
    public sealed class DbHelper
    {
        #region Properties

        private DbProviderFactory dbFactory;

        private string connectionName;

        private string connectionString;

        private const string contextKeyPrefix = "ruson_connection";        
        /// <summary>
        /// 连接上下文Key。
        /// </summary>
        public static string ContextKeyPrefix
        {
            get { return contextKeyPrefix; }
        }

        /// <summary>
        /// 指示是否使用持续的连接(操作完毕后不立即关闭连接)。
        /// </summary>
        public static bool ContinuedConnection
        {
            get; internal set;
        }

        #endregion

        #region Constructor

        /// <summary>
        /// 始初化 DbHelper 类的新实例。
        /// </summary>
        /// <param name="connectionName">连接字符串配置文件节中的单个命名连接字符串名。</param>
        public DbHelper(string connectionName)
        {
            if (string.IsNullOrEmpty(connectionName) || ConfigurationManager.ConnectionStrings[connectionName] == null)
                throw new ArgumentNullException("connectionName");

            ConnectionStringSettings setting = ConfigurationManager.ConnectionStrings[connectionName];           
            dbFactory = DbProviderFactories.GetFactory(setting.ProviderName);
            this.connectionName = connectionName;
            connectionString = setting.ConnectionString;           
        }

        #endregion

        #region Methods

        /// <summary>
        /// 返回实现 DbCommand 类的提供程序的类的一个新实例。
        /// </summary>
        /// <returns>DbCommand 实例。</returns>
        public DbCommand CreateCommand()
        {           
            return dbFactory.CreateCommand();
        }        

        /// <summary>
        /// 返回实现 DbConnection 类的提供程序的类的一个新实例。
        /// </summary>
        /// <returns>DbConnection 实例。</returns>
        public DbConnection CreateConnection()
        {
            DbConnection conn = null;            

            if (ContinuedConnection)
            {
                string key = string.Format("{0}_{1}", ContextKeyPrefix, connectionName);
                conn = GenericContext.Current[key] as DbConnection;

                if (conn == null)
                {                    
                    conn = dbFactory.CreateConnection();
                    conn.ConnectionString = connectionString;
                    GenericContext.Current[key] = conn;
                }
            }
            else
            {
                conn = dbFactory.CreateConnection();
                conn.ConnectionString = connectionString;
            }

            if (conn.State != ConnectionState.Open)
                conn.Open();
            return conn;
        }

        /// <summary>
        /// 返回实现 DbDataAdapter 类的提供程序的类的一个新实例。
        /// </summary>
        /// <returns>DbDataAdapter 实例。</returns>
        public DbDataAdapter CreateDataAdapter()
        {
            return dbFactory.CreateDataAdapter();
        }

        /// <summary>
        /// 返回实现 DbParameter 类的提供程序的类的一个新实例。
        /// </summary>
        /// <returns>DbParameter 实例。</returns>
        public DbParameter CreateParameter()
        {
            return dbFactory.CreateParameter();
        }

        /// <summary>
        /// 准备一个数据操作命令实例。
        /// </summary>
        /// <param name="conn">数据库连接实例。</param>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <param name="cmdType">CommandType 值之一。</param>
        /// <param name="cmdParams">SQL 语句或存储过程的参数。</param>
        /// <returns>DbCommand 实例。</returns>
        protected DbCommand PrepareCommand(DbConnection conn, string cmdText, CommandType cmdType, params IDataParameter[] cmdParams)
        {
            DbCommand cmd = CreateCommand();
            cmd.Connection = conn;
            cmd.CommandText = cmdText;
            cmd.CommandType = cmdType;

            if (cmdParams != null)
            {
                foreach (IDataParameter param in cmdParams)
                {                   
                    cmd.Parameters.Add(param);
                }
            }
           
            return cmd;
        }

        /// <summary>
        /// 执行数据操作，返回首行首列值。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <param name="cmdType">CommandType 值之一。</param>
        /// <param name="cmdParams">SQL 语句或存储过程的参数。</param>
        /// <returns>首行首列值，未查询到数据时返回null。</returns>
        public object ExecuteScalar(string cmdText, CommandType cmdType, params IDataParameter[] cmdParams)
        {
            object val;

            DbConnection conn = CreateConnection();

            if (ContinuedConnection)
            {
                using (DbCommand cmd = PrepareCommand(conn, cmdText, cmdType, cmdParams))
                {                    
                    val = cmd.ExecuteScalar();                    
                    cmd.Parameters.Clear();
                }
            }
            else
            {
                using (conn)
                {
                    using (DbCommand cmd = PrepareCommand(conn, cmdText, cmdType, cmdParams))
                    {
                        conn.Open();
                        val = cmd.ExecuteScalar();
                        conn.Close();
                        cmd.Parameters.Clear();
                    }
                }
            }

            return val;
        }

        /// <summary>
        /// 执行数据操作，返回首行首列值。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <param name="cmdParams">SQL 语句或存储过程的参数。</param>
        /// <returns>首行首列值，未查询到数据时返回null。</returns>
        public object ExecuteScalar(string cmdText, params IDataParameter[] cmdParams)
        {
            return ExecuteScalar(cmdText, CommandType.Text, cmdParams);
        }

        /// <summary>
        /// 执行数据操作，返回首行首列值。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <returns>首行首列值，未查询到数据时返回null。</returns>
        public object ExecuteScalar(string cmdText)
        {
            return ExecuteScalar(cmdText, CommandType.Text, null);
        }

        /// <summary>
        /// 执行数据操作，返回受影响行数。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句。</param>
        /// <param name="cmdType">CommandType 值之一。</param>
        /// <param name="cmdParams">SQL 语句的参数。</param>
        /// <returns>受影响行数。</returns>
        public int ExecuteNonQuery(string cmdText, CommandType cmdType, params IDataParameter[] cmdParams)
        {
            DbConnection conn = CreateConnection();

            if (ContinuedConnection)
            {
                using (DbCommand cmd = PrepareCommand(conn, cmdText, cmdType, cmdParams))
                {                    
                    int val = cmd.ExecuteNonQuery();                    
                    cmd.Parameters.Clear();
                    return val;
                }
            }
            else
            {
                using (conn)
                {
                    using (DbCommand cmd = PrepareCommand(conn, cmdText, cmdType, cmdParams))
                    {
                        conn.Open();
                        int val = cmd.ExecuteNonQuery();
                        conn.Close();
                        cmd.Parameters.Clear();
                        return val;
                    }
                }
            }
        }

        /// <summary>
        /// 执行数据操作，返回受影响行数。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句。</param>
        /// <param name="cmdType">CommandType 值之一。</param>
        /// <returns>受影响行数。</returns>
        public int ExecuteNonQuery(string cmdText, CommandType cmdType)
        {
            return ExecuteNonQuery(cmdText, cmdType, null);
        }

        /// <summary>
        /// 执行数据操作，返回受影响行数。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句。</param>
        /// <param name="cmdParams">SQL 语句的参数。</param>
        /// <returns>受影响行数。</returns>
        public int ExecuteNonQuery(string cmdText, params IDataParameter[] cmdParams)
        {
            return ExecuteNonQuery(cmdText, CommandType.Text, cmdParams);
        }

        /// <summary>
        /// 执行数据操作，返回受影响行数。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句。</param>
        /// <returns>受影响行数。</returns>
        public int ExecuteNonQuery(string cmdText)
        {
            return ExecuteNonQuery(cmdText, CommandType.Text, null);
        }

        /// <summary>
        /// 执行数据操作，返回 DbDataReader。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <param name="cmdType">CommandType 值之一。</param>
        /// <param name="cmdParams">SQL 语句或存储过程的参数。</param>
        /// <returns>DbDataReader 实例。</returns>
        public DbDataReader ExecuteReader(string cmdText, CommandType cmdType, params IDataParameter[] cmdParams)
        {
            DbConnection conn = CreateConnection();

            if (ContinuedConnection)
            {
                using (DbCommand cmd = PrepareCommand(conn, cmdText, cmdType, cmdParams))
                {                    
                    DbDataReader dr = cmd.ExecuteReader();
                    cmd.Parameters.Clear();
                    return dr;
                }
            }
            else
            {
                using (conn)
                {
                    using (DbCommand cmd = PrepareCommand(conn, cmdText, cmdType, cmdParams))
                    {
                        conn.Open();
                        DbDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                        cmd.Parameters.Clear();
                        return dr;
                    }
                }
            }
        }

        /// <summary>
        /// 执行数据操作，返回 DbDataReader。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <param name="cmdParams">SQL 语句或存储过程的参数。</param>
        /// <returns>DbDataReader 实例。</returns>
        public DbDataReader ExecuteReader(string cmdText, params IDataParameter[] cmdParams)
        {
            return ExecuteReader(cmdText, CommandType.Text, cmdParams);
        }

        /// <summary>
        /// 执行数据操作，返回 DbDataReader。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <param name="cmdType">CommandType 值之一。</param>
        /// <returns>DbDataReader 实例。</returns>
        public DbDataReader ExecuteReader(string cmdText, CommandType cmdType)
        {
            return ExecuteReader(cmdText, cmdType, null);
        }

        /// <summary>
        /// 执行数据操作，返回 DbDataReader。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <returns>DbDataReader 实例。</returns>
        public DbDataReader ExecuteReader(string cmdText)
        {
            return ExecuteReader(cmdText, CommandType.Text, null);
        }
       
        /// <summary>
        /// 执行数据操作，返回 DataSet。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <param name="cmdType">CommandType 值之一。</param>
        /// <param name="cmdParams">SQL 语句或存储过程的参数。</param>
        /// <returns>DataSet 实例。</returns>
        public DataSet ExecuteDataSet(string cmdText, CommandType cmdType, params IDataParameter[] cmdParams)
        {
            DataSet ds = new DataSet();

            DbConnection conn = CreateConnection();

            if (ContinuedConnection)
            {
                using (DbDataAdapter da = CreateDataAdapter())
                {
                    using (DbCommand cmd = PrepareCommand(conn, cmdText, cmdType, cmdParams))
                    {                        
                        da.SelectCommand = cmd;
                        da.Fill(ds);                        
                        cmd.Parameters.Clear();
                    }
                }
            }
            else
            {
                using (conn)
                {
                    using (DbDataAdapter da = CreateDataAdapter())
                    {
                        using (DbCommand cmd = PrepareCommand(conn, cmdText, cmdType, cmdParams))
                        {
                            conn.Open();
                            da.SelectCommand = cmd;
                            da.Fill(ds);
                            conn.Close();
                            cmd.Parameters.Clear();
                        }
                    }
                }
            }

            return ds;
        }

        /// <summary>
        /// 执行数据操作，返回 DataSet。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <returns>DataSet 实例。</returns>
        public DataSet ExecuteDataSet(string cmdText)
        {
            return ExecuteDataSet(cmdText, CommandType.Text, null);
        }

        /// <summary>
        /// 执行数据操作，返回 DataSet。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>
        /// <param name="cmdType">CommandType 值之一。</param>
        /// <returns>DataSet 实例。</returns>
        public DataSet ExecuteDataSet(string cmdText, CommandType cmdType)
        {
            return ExecuteDataSet(cmdText, cmdType, null);
        }    

        /// <summary>
        /// 执行数据操作，返回 DataSet。
        /// </summary>
        /// <param name="cmdText">要执行的 SQL 语句或存储过程。</param>       
        /// <param name="cmdParams">SQL 语句或存储过程的参数。</param>
        /// <returns>DataSet 实例。</returns>
        public DataSet ExecuteDataSet(string cmdText, params IDataParameter[] cmdParams)
        {
            return ExecuteDataSet(cmdText, CommandType.Text, cmdParams);
        }

        /// <summary>
        /// 返回 DbParameter 类的一个新实例。
        /// </summary>
        /// <param name="name">要映射的参数的名称。</param>
        /// <param name="type">DbType 值之一。</param>
        /// <param name="size">列中数据的最大大小（以字节为单位）</param>
        /// <param name="pd">ParameterDirection 值之一。默认为 Input。</param>
        /// <returns>DbParameter 实例。</returns>
        public DbParameter NewParam(string name, DbType type, int size, ParameterDirection pd)
        {
            DbParameter param = CreateParameter();
            param.ParameterName = name;
            param.DbType = type;
            param.Size = size;
            param.Direction = pd;
            return param;
        }

        /// <summary>
        /// 返回 DbParameter 类的一个新实例。
        /// </summary>
        /// <param name="name">要映射的参数的名称。</param>
        /// <param name="type">DbType 值之一。</param>
        /// <param name="size">列中数据的最大大小（以字节为单位）。</param>
        /// <param name="value">新 DbParameter 实例的值。</param>
        /// <returns>DbParameter 实例。</returns>
        public DbParameter NewParam(string name, DbType type, int size, object value)
        {
            DbParameter param = CreateParameter();
            param.ParameterName = name;
            param.DbType = type;
            param.Size = size;
            if (value != null)
                param.Value = value;
            else
                param.Value = DBNull.Value;
            return param;
        }
       
        /// <summary>
        /// 返回 DbParameter 类的一个新实例。
        /// </summary>
        /// <param name="name">要映射的参数的名称。</param>
        /// <param name="type">DbType 值之一。</param>
        /// <param name="value">新 DbParameter 实例的值。</param>
        /// <returns>DbParameter 实例。</returns>
        public DbParameter NewParam(string name, DbType type, object value)
        {
            DbParameter param = CreateParameter();
            param.ParameterName = name;
            param.DbType = type;
            if (value != null)
                param.Value = value;
            else
                param.Value = DBNull.Value;
            return param;
        }

        /// <summary>
        /// 返回 DbParameter 类的一个新实例。
        /// </summary>
        /// <param name="name">要映射的参数的名称。</param>
        /// <param name="value">新 DbParameter 实例的值。</param>
        /// <returns>DbParameter 实例。</returns>
        public DbParameter NewParam(string name, object value)
        {
            DbParameter param = CreateParameter();
            param.ParameterName = name;
            param.Value = value;
            return param;
        }

        #endregion
    }
}